<template>
  <n-spin :show="mainStore.pageLoading" class="openapi-container">
    <div class="openapi-content">
      <n-h2 class="text-center">开放API</n-h2>
      <n-h4 v-if="openApiState.token" class="my-6 leading-7 text-center">
        以最低的价格（官网定价）解决开发者的问题！
      </n-h4>
      <n-h4 v-if="openApiState.token" class="my-6 leading-7 text-center">
        由于业务特殊性质，一经充值无法退款，请按需充值。
      </n-h4>
      <n-h4 v-else-if="!mainStore.pageLoading" class="my-6 leading-7 text-center">
        将专属机器人接入到您的程序中？点击下方开通Api服务按钮开始使用。
      </n-h4>
      <n-grid v-if="openApiState.token" x-gap="xs:16 s:20" y-gap="xs:16 s:20" cols="xs:1 s:2" responsive="screen">
        <n-gi>
          <n-alert class="my-token rounded-lg h-full" title="" type="default" :bordered="false">
            <div class="text-base">
              我的Token密钥，当前Token状态：
              <n-text v-if="openApiState.state === 1" type="success">正常</n-text>
              <n-text v-else type="error">禁用</n-text>
            </div>
            <template #icon>
              <n-icon :component="CodeSlashOutline" />
            </template>
            <n-input
              v-model:value="openApiState.token"
              class="my-4 h-11 flex items-center"
              readonly
              placeholder="暂未生成Token"
            >
              <template #suffix>
                <n-button text @click.stop="copyText(openApiState.token)">
                  <template #icon>
                    <n-icon :component="CopyOutline" />
                  </template>
                </n-button>
              </template>
            </n-input>
            <n-button size="large" type="primary" :loading="openApiState.btnLoading" @click="resetToken">
              重置Token
            </n-button>
          </n-alert>
        </n-gi>
        <n-gi>
          <n-alert class="my-token rounded-lg h-full" title="" type="default" :bordered="false">
            <div class="text-base">
              当前Token余额：
              <n-text type="success">{{ openApiState.point }}</n-text>
              点，转换比例：1元=100点
            </div>
            <template #icon>
              <n-icon :component="WalletOutline" />
            </template>
            <n-input-number v-model:value="openApiState.money" :min="30" class="my-4" placeholder="请输入要充值的金额">
              <template #prefix>
                <n-icon :component="LogoYen" class="mt-[-2px]" />
              </template>
            </n-input-number>
            <div class="flex gap-4">
              <n-button v-if="!isWeiXin()" size="large" color="#009FE8" @click="handlePay('alipay')">支付宝</n-button>
              <n-button size="large" color="#15BA11" @click="handlePay('wechat')">微信支付</n-button>
            </div>
          </n-alert>
        </n-gi>
      </n-grid>
      <n-alert
        v-else-if="!mainStore.pageLoading"
        class="bg-transparent"
        title=""
        type="default"
        :bordered="false"
        :show-icon="false"
      >
        <div class="flex gap-4 justify-center items-center">
          <n-button
            class="w-60 h-12"
            size="large"
            type="primary"
            :loading="openApiState.btnLoading"
            @click="generateToken"
          >
            开通API服务
          </n-button>
        </div>
      </n-alert>
      <VMdPreview
        v-if="openApiState.token"
        class="bg-[#fafafc] dark:bg-slate-500/20 py-4 px-6 mt-4 rounded-lg shadow-sm"
        :text="openApiMd"
      />
    </div>
  </n-spin>
  <BasicModal
    title="Token充值"
    to=".openapi-container"
    class="w-auto max-w-[520px] s:mx-auto"
    :mask-closable="false"
    @register="tokenModalRegister"
    @after-leave="afterPayLeave"
  >
    <div class="s:w-[450px]">
      <n-alert class="mb-4" title="" type="warning" :bordered="false">
        付款成功前请不要关闭此窗口，请按实际情况点击下方按钮。
      </n-alert>
      <n-card v-if="openApiState.paymentMethod === 'alipay'" class="pay-card" :bordered="false">
        <n-text class="text-lg">请在新打开的页面完成付款</n-text>
        <n-text class="text-base mt-2">订单号：{{ openApiState.order_number }}</n-text>
        <n-h4 class="flex justify-center items-baseline mt-2">
          支付金额：￥
          <n-text class="font-bold mb-0 text-2xl">{{ openApiState.money }}</n-text>
        </n-h4>
      </n-card>
      <n-card v-if="openApiState.paymentMethod === 'wechat'" class="pay-card" :bordered="false">
        <n-text class="text-lg">微信扫码支付</n-text>
        <n-text class="text-base">订单号：{{ openApiState.order_number }}</n-text>
        <n-spin class="qrcode-spin" :show="openApiState.loading">
          <div v-if="!openApiState.qrcodeUrl && !openApiState.loading" class="qrcode-expired">
            <n-text class="text-white/80">二维码已超时</n-text>
            <n-button type="primary" @click="getQrcode">刷新</n-button>
          </div>
          <qrcode-vue
            class="my-4 border rounded"
            :value="openApiState.qrcodeUrl"
            render-as="svg"
            :margin="2"
            :size="240"
            level="L"
          />
        </n-spin>
        <n-h4 class="flex justify-center items-baseline">
          支付金额：￥
          <n-text class="font-bold mb-0 text-2xl">{{ openApiState.money }}</n-text>
        </n-h4>
      </n-card>
    </div>
    <template #action>
      <div class="w-full flex gap-4 justify-center">
        <n-button type="default" size="large" @click="basicCloseTokenModal">取消支付</n-button>
        <n-button type="primary" size="large" :loading="openApiState.checkIng" @click="payComplete">付款成功</n-button>
      </div>
    </template>
  </BasicModal>
</template>

<script setup>
import { reactive, defineAsyncComponent } from 'vue'
import { useMainStore } from '@/store'
import { useRouter } from 'vue-router'
import { obtainToken, createResetToken } from '@api/userApi'
import { checkOrder, wechatBuy, alipay } from '@api/payApi'
import { copyText, isWeiXin } from '@/utils'
import { CopyOutline, CodeSlashOutline, LogoYen, WalletOutline } from '@vicons/ionicons5'
import { useModal } from '@cmps/Modal/useModal'
import { isNumber } from '@vueuse/core'
import VMdPreview from '@/plugins/vmdPreview'
import openApiMd from '@/assets/files/openApi.md?raw'
import { useDialog } from '@/hook/useDialog'

const QrcodeVue = defineAsyncComponent(() => import('qrcode.vue'))
const BasicModal = defineAsyncComponent(() => import('@cmps/Modal/BasicModal.vue'))

const router = useRouter()

const mainStore = useMainStore()

const openApiState = reactive({
  token: '',
  state: null,
  point: 0,
  money: 30,
  second: 0,
  btnLoading: false,
  qrcodeUrl: '',
  order_number: '',
  checkIng: false,
  checkOrderTimer: null,
  loading: false,
  paymentMethod: null,
})

const [tokenModalRegister, { openModal: basicOpenTokenModal, closeModal: basicCloseTokenModal }] = useModal({})

const getToken = async () => {
  try {
    mainStore.setPageLoading(true)
    const res = await obtainToken()
    if (res.statusCode === 200) {
      if (res.data) {
        const { user_token, have_point, state } = res.data
        openApiState.token = user_token
        openApiState.point = have_point
        openApiState.state = state
      }
    }
  } finally {
    mainStore.setPageLoading(false)
  }
}
getToken()

const generateToken = async () => {
  try {
    openApiState.btnLoading = true
    const res = await createResetToken()
    if (res.statusCode === 200) {
      $message.success(res.msg, { duration: 1000 })
      openApiState.token = res.data
      openApiState.state = 1
    }
  } finally {
    openApiState.btnLoading = false
  }
}

const resetToken = () => {
  let tokenDialog = useDialog({
    title: '提示',
    content: '是否重置当前Token？',
    type: 'warning',
    icon: true,
    async confirm() {
      await generateToken()
      tokenDialog = null
      tokenDialog && tokenDialog.destroy()
    },
    cancel() {},
  })
}

const handlePay = async type => {
  if (isNumber(openApiState.money) && openApiState.token) {
    openApiState.paymentMethod = type
    switch (type) {
      case 'wechat':
        basicOpenTokenModal()
        getQrcode()
        break
      case 'alipay':
        basicOpenTokenModal()
        try {
          openApiState.second = 0
          openApiState.loading = true
          const res = await alipay({
            recharge: openApiState.money,
            return_url: location.href,
          })
          if (res.statusCode === 200) {
            const { form, order_number } = res.data
            openApiState.order_number = order_number
            $message.loading('正在发起支付中', { duration: 1000 })
            setTimeout(() => {
              openApiState.checkOrderTimer = setInterval(checkOrderStatus, 2000)
              const routerData = router.resolve({ path: '/alipay', query: { htmlData: form } })
              window.open(`${location.origin}${routerData.href}`, '_blank')
            }, 1000)
          }
        } finally {
          openApiState.loading = false
        }
        break
    }
  } else {
    $message.error('充值金额有误', { duration: 1000 })
  }
}

const getQrcode = async () => {
  try {
    openApiState.second = 0
    openApiState.loading = true
    const res = await wechatBuy({ type: 'Native', recharge: openApiState.money })
    if (res.statusCode === 200) {
      openApiState.qrcodeUrl = res.data.code_url
      openApiState.order_number = res.data.order_number
      openApiState.checkOrderTimer = setInterval(checkOrderStatus, 2000)
    }
  } finally {
    openApiState.loading = false
  }
}

const checkOrderStatus = async () => {
  try {
    openApiState.second += 2
    if (openApiState.paymentMethod === 'wechat') {
      const res = await checkOrder({ order_number: openApiState.order_number })
      if (res.statusCode === 200) {
        if (res.state === 1) {
          $message.success('支付成功')
          basicCloseTokenModal()
          await getToken()
        }
      }
    }
  } finally {
    if (openApiState.second >= 300) {
      afterPayLeave()
    }
  }
}

const payComplete = async () => {
  try {
    openApiState.checkIng = true
    const res = await checkOrder({ order_number: openApiState.order_number })
    if (res.statusCode === 200) {
      if (res.state === 1) {
        basicCloseTokenModal()
        await getToken()
        $message.success('支付成功')
      } else {
        $message.warning('暂未支付', { duration: 1500 })
      }
    }
  } finally {
    openApiState.checkIng = false
  }
}

const afterPayLeave = () => {
  if (openApiState.paymentMethod === 'alipay' && openApiState.second >= 300) {
    basicCloseTokenModal()
    useDialog({
      type: 'error',
      icon: true,
      title: '提示',
      content: '当前支付已超时！',
      negative: '',
      confirm() {},
    })
  }
  openApiState.qrcodeUrl = ''
  openApiState.order_number = null
  openApiState.loading = false
  clearInterval(openApiState.checkOrderTimer)
  openApiState.checkOrderTimer = null
  openApiState.second = 0
  openApiState.paymentMethod = null
}
</script>

<style lang="less" scoped>
.openapi-container {
  &:deep(.openapi-content) {
    max-width: 930px;
    margin: 0 auto;

    .n-alert {
      box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
    }

    .my-token {
      .n-alert__icon {
        margin-top: 16px;
      }

      .n-alert-body {
        padding: 16px 16px 16px 44px;
        .n-input-number {
          .n-input {
            height: 44px;
            display: flex;
            align-items: center;
          }
        }
      }
    }
  }

  &:deep(.pay-card) {
    .n-card__content {
      padding: 0 0 14px;
      display: flex;
      justify-content: center;
      align-items: center;
      flex-direction: column;

      .qrcode-spin {
        .n-spin-content {
          position: relative;

          .qrcode-expired {
            width: 100%;
            height: 100%;
            position: absolute;
            z-index: 10;
            left: 0;
            top: 0;
            display: flex;
            align-items: center;
            justify-content: center;
            flex-direction: column;
            gap: 10px;
            backdrop-filter: saturate(150%) contrast(50%) blur(8px);
            -webkit-backdrop-filter: saturate(150%) contrast(50%) blur(8px);
            background-color: rgba(0, 0, 0, 0.3);
          }
        }
      }
    }
  }
}
</style>
